#include<iostream>
#include<WinSock2.h>
#include <thread>
#include<string>
#include <time.h>
#include<fstream>

#pragma warning(disable:4996)
#pragma comment (lib, "ws2_32.lib")  //加载 ws2_32.dll
using namespace std;
clock_t start;
char* buf = new char[8];

const int win = 10;//窗口大小
int win_head = 0, win_tail = 10;//窗口左边缘和右边缘，如果超时则赋值【i=win_head-1】然后continue
unsigned char init_seq;
int len;
int MISCOUNT = 100;//丢包率，指定每过100个包故意丢一个包
bool resend = false;//配合丢包，如果为false说明这个包头一次来，就该故意丢，否则是重发的，认真对待
SOCKET sock;
struct sockaddr_in sockAddr;//sockaddr_in用作定义，socketaddr用作函数参数
bool transmitting = true;

const int MAXBUF = 1024;
const double TIMEOUT = 2 * CLOCKS_PER_SEC;
#define SYN 4
#define ACK 2
#define FIN 1
#define ACK_SYN 6
#define ACK_FIN 3
#define OVER 5

struct HEADER {
	u_short len = 0;//2
	u_short ck_sum = 0;//2
	u_short flag = 0;//[SYN ACK FIN]	//2
	unsigned char seq_num = 0;//1
	unsigned char ack_num = 0;//1
}head;
u_short cksum(u_short* mes, int count) {//u_short宏定义为short类型，占2个字节；以16位为单位取报文(mes) 
	//mes指向报文，count表示报文-16位 为单位的组数
	u_long sum = 0;
	while (count--) {
		sum += *mes++;//以16位为单位累加
		if (sum & 0xffff0000) {//如果超出了两个字节，说明有溢出
			sum &= 0xffff;//只保留低两个字节
			sum++;
		}
	}
	return ~(sum & 0xffff);
}
void update_ACK() {
	u_long mode = 1;//非阻塞，否则recv函数会一直等待
	ioctlsocket(sock, FIONBIO, &mode);
	while (transmitting) {
		recvfrom(sock, buf, 8, 0, (sockaddr*)&sockAddr, (&len));
		HEADER* recv_head = (HEADER*)buf;
		if ((recv_head->ack_num > (win_head + init_seq) % 256) || ((recv_head->ack_num < (win_head + init_seq) % 256) && ((int)recv_head->ack_num + 1) % 256 > (win_head + init_seq + 1) % 256)) {
			//printf("\n\n对方期待SEQ=%d,且此时的win_head为%d\n\n", recv_head->ack_num, (win_head) % 256);
			//while ((++win_head) % 256 != recv_head->ack_num);
			int gap = (int)recv_head->ack_num - (int)(win_head + init_seq) % 256;

			if (gap < 0) {
				gap = (int)gap + 256;
			}
			win_head += gap;
			win_tail = win_head + win;//调节尾部，窗口后移
			printf("发送窗口的HEAD-%d,TAIL-%d\n", win_head, win_tail);
			start = clock();
		}
	}
}
int main() {
	cout << "客户端" << endl;
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);//希望用户使用2.2版本的Socket
	sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

	memset(&sockAddr, 0, sizeof(sockAddr));  //将结构体清零
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//指定服务器IP
	sockAddr.sin_port = htons(1234);//指定服务器端口
	//shake(sock, (SOCKADDR*)&sockAddr);

	sockaddr_in C_sockAddr;
	memset(&C_sockAddr, 0, sizeof(C_sockAddr));
	C_sockAddr.sin_family = AF_INET;//IPv4
	C_sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//客户端
	C_sockAddr.sin_port = htons(6666);//客户端绑定端口
	bind(sock, (sockaddr*)&C_sockAddr, sizeof(C_sockAddr));


	//-----------------------------三次握手-----------------------------
	len = sizeof(sockAddr);
	head.len = 8;//8个字节
	head.flag = SYN;
	srand((unsigned)time(NULL));
	head.seq_num = rand() % (MAXBYTE);//产生随机序列号
	cout << "第一次握手的Seq序列号为：" << (int)head.seq_num << endl;
	cout << "第一次握手的Ack序列号为：" << (int)head.ack_num << endl;
	head.ack_num = 0;
	head.ck_sum = 0;
	head.ck_sum = cksum((u_short*)&head, head.len / 2 + head.len % 2);


	memcpy(buf, &head, head.len);
	clock_t start;

	sendto(sock, buf, head.len, 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));

	cout << endl << "等待第二次握手中....." << endl;
	start = clock();
	//接收第二次握手
	HEADER* recv_head;
	u_long mode = 1;//非阻塞，否则recv函数会一直等待
	ioctlsocket(sock, FIONBIO, &mode);
	while (1) {
		if (clock() - start > TIMEOUT) {
			cout << "超时...重传中..." << endl;
			sendto(sock, buf, head.len, 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));
			cout << endl << "等待第二次握手中....." << endl;
			start = clock();
		}
		else {
			recvfrom(sock, buf, 8, 0, (sockaddr*)&sockAddr, (&len));
			recv_head = (HEADER*)buf;
			if (cksum((u_short*)buf, 4) != 0x0000) {
				cout << "error!第二次握手传输中出现错误！" << endl;//等待重传
			}
			else {
				if (recv_head->flag == ACK_SYN) {
					cout << "成功接收第二次握手内容!" << endl;
					cout << "第二次握手中Ack为" << (int)recv_head->ack_num << endl;
					cout << "第二次握手中Seq为" << (int)recv_head->seq_num << endl;
					break;
				}
			}
		}
	}
	//发送第三次握手内容
	cout << endl << "进行第三次握手:" << endl;

	head.flag = ACK;
	srand((unsigned)time(NULL));
	head.seq_num = recv_head->ack_num;//产生随机序列号
	head.ack_num = recv_head->seq_num + 1;
	cout << "第三次握手中Ack为" << (int)recv_head->ack_num << endl;
	cout << "第三次握手中Seq为" << (int)recv_head->seq_num << endl;

	char filename[50] = { 0 };
	cout << "请输入待传输文件名称:";
	cin >> filename;
	//filename = "1.jpg";

	head.len = sizeof(HEADER) + strlen(filename);//数据包大小
	head.ck_sum = 0;
	memcpy(buf, &head, sizeof(HEADER));
	memcpy(buf + sizeof(HEADER), &filename, strlen(filename));
	head.ck_sum = cksum((u_short*)buf, head.len / 2 + head.len % 2);
	memcpy(buf, &head, sizeof(HEADER));
	//cout << "len:" << head.len << endl;
	//cout << "sum=" << cksum((u_short*)buf, head.len / 2 + head.len % 2) << endl;

	while (sendto(sock, buf, head.len, 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR) {
		cout << "send发送失败！重新发送..." << endl;
	}
	cout << "第三次握手已发送.....可以进行数据传输..." << endl;

	//-----------------------------三次握手-----------------------------
	// 
	// 
	//-----------------------------传输数据-----------------------------

	ifstream f_send;
	bool type = 0;//表示文本
	if (strcmp(&filename[strlen(filename) - 3], "jpg")) {//文本文件
		f_send.open(filename, ios::in);
	}
	else {
		f_send.open(filename, ios::binary);
		type = 1;//表示图片
	}
	if (!f_send.is_open()) {
		cout << "File does not exist. " << endl;
		return 0;
	}
	//计算文件大小
	f_send.seekg(0, f_send.end);
	int pic_length = f_send.tellg();
	f_send.seekg(0, f_send.beg);


	int pkg_num = pic_length / MAXBUF + (pic_length % MAXBUF == 0);
	cout << "pkg_num:" << pkg_num << endl;
	char* buff = new char[MAXBUF + sizeof(HEADER)];
	char* buffer = new char[MAXBUF + 1];

	head.seq_num = head.seq_num + 1;//第一个包产生随机序列号
	head.ack_num = 0;
	head.len = MAXBUF + sizeof(HEADER);
	head.flag = ACK;
	srand((unsigned)time(NULL));
	cout << endl << "数据发送中..." << endl;


	thread t1(update_ACK);
	t1.detach();//循环更新recv_ack的值

	init_seq = head.seq_num;
	clock_t start_send = clock();
	start = clock();//开启计时
	for (int i = 0; i < pkg_num; i++) {
		if (clock() - start > TIMEOUT) {
			//cout << "此时WIN_HEAD为" << win_head << endl;
			//cout << "超时...重传窗口中的所有数据包中..." << endl;
			cout << "从SEQ = " << (win_head + init_seq) % 256 << "开始的数据包开始重发" << endl << endl;
			i = win_head - 1;
			start = clock();
			continue;
		}
		if (i > win_tail) {
			//cout << ".";
			i--;
			continue;
		}
		if (i % MISCOUNT == 0) {//头一次发的话是false
			resend = !resend;
			if (resend) {
				cout << "故意丢包！SEQ=" << ((int)init_seq + i) % 256 << "的数据包被丢弃！" << endl;
				cout << "此时应该发送第" << i << "个数据包！" << endl;
				continue;
			}//若是头一次来则继续
		}


		f_send.seekg(i * MAXBUF, std::ios::beg);
		f_send.read(buffer, MAXBUF);//读取文件内容，存入buffer
		head.seq_num = ((int)init_seq + i) % 256;
		head.ck_sum = 0;
		memset(buff, 0, MAXBUF + sizeof(HEADER));
		memcpy(buff, &head, sizeof(HEADER));
		memcpy(buff + sizeof(HEADER), buffer, MAXBUF);
		head.ck_sum = cksum((u_short*)buff, head.len / 2 + head.len % 2);
		memcpy(buff, &head, sizeof(HEADER));
		//cout << "已发送SEQ=" << (int)head.seq_num << endl;
		sendto(sock, buff, MAXBUF + sizeof(HEADER), 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));
		//cout << "Msg size:" << (int)head.len << "bytes! FLAG:" << (int)head.flag << " SEQ:" << (int)head.seq_num << " SUM:" << (int)head.ck_sum << endl;

	}
	f_send.close();
	clock_t end_send = clock();
	cout << endl << "传输完成！！" << endl;
	cout << "传输总时间为:" << (double)((end_send - start_send) / CLOCKS_PER_SEC) << "s" << endl;
	cout << "吞吐率为:" << ((float)pic_length) / ((end_send - start_send) / CLOCKS_PER_SEC) << "byte/s" << endl;
	transmitting = false;//退出update_ACK函数
	//-----------------------------传输数据-----------------------------
	// 
	// 
	//-----------------------------四次挥手-----------------------------
	head.len = 8;//8个字节
	head.flag = ACK_FIN;
	srand((unsigned)time(NULL));
	head.seq_num = rand() % (MAXBYTE);//产生随机序列号
	unsigned char store_seq = head.seq_num;//保存这个seq值
	head.ack_num = rand() % (MAXBYTE);
	cout << endl << "第一次挥手的Seq序列号为：" << (int)head.seq_num << endl;
	cout << "第一次挥手的Ack序列号为：" << (int)head.ack_num << endl;
	head.ck_sum = 0;
	head.ck_sum = cksum((u_short*)&head, head.len / 2 + head.len % 2);
	memset(buf, 0, strlen(buf));
	memcpy(buf, &head, head.len);
	//cout << "第一次挥手的整体sum：" << cksum((u_short*)buf, 4) << endl;
	sendto(sock, buf, head.len, 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));//第一次挥手BYEBYE~
	start = clock();

	while (1) {
		if (clock() - start > TIMEOUT) {
			cout << "超时...重传第一次挥手中..." << endl;
			sendto(sock, buf, head.len, 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));//第一次挥手BYEBYE~
			start = clock();
		}
		else {
			memset(buffer, 0, 10);
			recvfrom(sock, buffer, 8, 0, (sockaddr*)&sockAddr, (&len));
			recv_head = (HEADER*)buffer;
			//cout << "收到的sum(2)：" << cksum((u_short*)buffer, 4) << endl;
			if (cksum((u_short*)buffer, 4) != 0x0000) {
				//	cout << "error!第二次挥手中出现错误！" << endl;//等待重传
			}
			else {
				if (recv_head->flag == ACK && recv_head->ack_num == ((int)head.seq_num + 1) % 256 && recv_head->seq_num == head.ack_num) {
					cout << endl << "成功进行第二次挥手!" << endl;
					cout << "第二次挥手接收到的ack:" << (int)recv_head->ack_num << endl;
					cout << "第二次挥手接收到的seq:" << (int)recv_head->seq_num << endl;
					break;//发下一个包
				}
			}
		}
	}
	do
	{
		recvfrom(sock, buffer, 8, 0, (sockaddr*)&sockAddr, (&len));
		recv_head = (HEADER*)buffer;
	} while (recv_head->flag != ACK_FIN);//接收第三次握手


	cout << endl << "成功进行第三次挥手..." << endl;
	cout << "第三次挥手接收到的ack:" << (int)recv_head->ack_num << endl;
	cout << "第三次挥手接收到的seq:" << (int)recv_head->seq_num << endl;

	head.len = 8;//8个字节
	head.flag = ACK;
	head.seq_num = recv_head->ack_num;
	head.ack_num = recv_head->seq_num + 1;
	cout << endl << "第四次挥手的Seq序列号为：" << (int)head.seq_num << endl;
	cout << "第四次挥手的Ack序列号为：" << (int)head.ack_num << endl;
	head.ck_sum = 0;
	head.ck_sum = cksum((u_short*)&head, head.len / 2 + head.len % 2);
	memset(buf, 0, strlen(buf));
	memcpy(buf, &head, head.len);
	sendto(sock, buf, head.len, 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));//第一次挥手BYEBYE~

	closesocket(sock);
	WSACleanup();
	return 0;
}
